<?php
namespace common\modules\modularity;

use common\core\modularity\ModuleServiceInterface;
use common\modules\modularity\models\Modularity;
use yii\base\Exception;

class ModularityService implements ModuleServiceInterface
{

    private $allModules = null;

    public function getServiceId()
    {
        return 'modularityService';
    }

    public function getActiveModules($app)
    {
        $ret = [];
        $field = "enable_$app";
        $allModules = Modularity::find()->where([
            $field => 1
        ])
            ->indexBy('id')
            ->orderBy('sort')
            ->all();
        
        $modules = $this->loadAllModules();
        foreach ($allModules as $m) {
            $moduleId = $m->id;
            $module = $modules[$moduleId];
            
            $ret[$moduleId]['id'] = $module['id'];
            $ret[$moduleId]['dir'] = $module['dir'];
            $ret[$moduleId]['dir_class'] = $module['dir_class'];
            $ret[$moduleId]['class'] = $module['class'];
            $ret[$moduleId]['instance'] = $module['instance'];
        }
        return $ret;
    }

    public function getAllModules()
    {
        $ret = [];
        
        $allModules = Modularity::find()->indexBy('id')->orderBy('sort')->all();
        
        $modules = $this->loadAllModules();
        foreach ($modules as $m) {
            $moduleId = $m['id'];
            
            $ret[$moduleId] = $m;
            if (array_key_exists($moduleId, $allModules)) {
                $exitModule = $allModules[$moduleId];
                
                if ($ret[$moduleId]['has_backend']) {
                    $ret[$moduleId]['can_active_backend'] = ($exitModule['enable_backend'] === null || $exitModule['enable_backend'] === 0) ? true : false;
                }
                if ($ret[$moduleId]['has_frontend']) {
                    $ret[$moduleId]['can_active_frontend'] = ($exitModule['enable_frontend'] === null || $exitModule['enable_frontend'] === 0) ? true : false;
                }
                if ($ret[$moduleId]['has_api']) {
                    $ret[$moduleId]['can_active_api'] = ($exitModule['enable_api'] === null || $exitModule['enable_api'] === 0) ? true : false;
                }
                
                $ret[$moduleId]['can_install'] = false;
                $ret[$moduleId]['can_uninstall'] = ($ret[$moduleId]['has_backend'] && $exitModule['enable_backend'] || $ret[$moduleId]['has_frontend'] && $exitModule['enable_frontend'] || $ret[$moduleId]['has_api'] && $exitModule['enable_api']) ? false : true;
            }
        }
        return $ret;
    }

    private function loadAllModules()
    {
        if ($this->allModules !== null) {
            return $this->allModules;
        }
        $this->allModules = [];
        
        $moduleRootPath = \Yii::getAlias('@common') . '/modules';
        $moduleRootDir = @ dir($moduleRootPath);
        if ($moduleRootDir) {
            while (($moduleFolder = $moduleRootDir->read()) !== false) {
                $currentModuleDir = $moduleRootPath . '/' . $moduleFolder;
                if (preg_match('|^\.+$|', $moduleFolder) || ! is_dir($currentModuleDir)) {
                    continue;
                }
                
                $moduleClassName = ucwords($moduleFolder);
                
                if (file_exists($currentModuleDir . '/' . 'ModuleInfo.php')) {
                    $class = 'common\modules\\' . $moduleFolder . '\\' . 'ModuleInfo';
                } else {
                    continue;
                }
                
                $instance = null;
                try {
                    $instance = new $class();
                    if (empty($instance->id)) {
                        $instance->id = $moduleFolder;
                    }
                    if (empty($instance->name)) {
                        $instance->name = $moduleFolder;
                    }
                    if ($instance->is_system) {
                        if (! Modularity::findOne([
                            'id' => $instance->id
                        ])) {
                            $model = new Modularity();
                            $model->id = $instance->id;
                            $model->enable_backend = $instance->has_backend;
                            $model->enable_frontend = $instance->has_frontend;
                            $model->enable_api = $instance->has_api;
                            $model->save(false);
                    
                            $instance->install();
                        }
                    }
                } catch (Exception $e) {
                    $instance = null;
                }
                
                if ($instance !== null) {
                    $has_backend = file_exists($currentModuleDir . '/backend/Module.php') ? true : false;
                    $has_frontend = file_exists($currentModuleDir . '/frontend/Module.php') ? true : false;
                    $has_api = file_exists($currentModuleDir . '/api/Module.php') ? true : false;
                    
                    $this->allModules[$instance->id] = [
                        'id' => $instance->id,
                        'dir' => $moduleFolder,
                        'dir_class' => $moduleClassName,
                        'class' => $class,
                        'instance' => $instance,
                        'can_install' => true,
                        'can_uninstall' => true,
                        'has_backend' => $has_backend,
                        'has_frontend' => $has_frontend,
                        'has_api' => $has_api,
                        'can_active_backend' => false,
                        'can_active_frontend' => false,
                        'can_active_api' => false
                    ];
                }
            }
        }
        return $this->allModules;
    }
    
    public function getAllBackendMenus()
    {
        $backendModules = $this->getActiveModules('backend');
        $ret = [];
        foreach ($backendModules as $m) {
            $moduleId = $m['id'];
            $module = \Yii::$app->getModule($moduleId);
            $instance = $m['instance'];
            $item = [];
            $item['label'] =$instance->name;
            $item['url'] = '#';
            $item['icon'] = $instance->icon;
            if ($module) {
                $item['options'] = [
                    'class' => 'treeview'
                ];
                $item['items'] = $module->getMenus();
            }
            $ret[] = $item;
        }
        return $ret;
    }
    
    public function installSystemModules()
    {
        if ($this->allModules !== null) {
            return $this->allModules;
        }
        $this->allModules = [];
        
        $moduleRootPath = \Yii::getAlias('@common') . '/modules';
        $moduleRootDir = @ dir($moduleRootPath);
        if ($moduleRootDir) {
            while (($moduleFolder = $moduleRootDir->read()) !== false) {
                $currentModuleDir = $moduleRootPath . '/' . $moduleFolder;
                if (preg_match('|^\.+$|', $moduleFolder) || ! is_dir($currentModuleDir)) {
                    continue;
                }
        
                $moduleClassName = ucwords($moduleFolder);
        
                if (file_exists($currentModuleDir . '/' . 'ModuleInfo.php')) {
                    $class = 'common\modules\\' . $moduleFolder . '\\' . 'ModuleInfo';
                } else {
                    continue;
                }
        
                $instance = null;
                try {
                    $instance = new $class();
                    if (empty($instance->id)) {
                        $instance->id = $moduleFolder;
                    }
                    if (empty($instance->name)) {
                        $instance->name = $moduleFolder;
                    }
                    if ($instance->is_system) {
                        if (! Modularity::findOne([
                            'id' => $instance->id
                        ])) {
                            $model = new Modularity();
                            $model->id = $instance->id;
                            $model->enable_backend = $instance->has_backend;
                            $model->enable_frontend = $instance->has_frontend;
                            $model->enable_api = $instance->has_api;
                            $model->save(false);
                            
                            $instance->install();
                        }
                    }
        
                } catch (Exception $e) {
                    $instance = null;
                }
            }
        }
    }
    
    public function uninstallSystemModules()
    {
        if ($this->allModules !== null) {
            return $this->allModules;
        }
        $this->allModules = [];
        
        $moduleRootPath = \Yii::getAlias('@common') . '/modules';
        $moduleRootDir = @ dir($moduleRootPath);
        if ($moduleRootDir) {
            while (($moduleFolder = $moduleRootDir->read()) !== false) {
                $currentModuleDir = $moduleRootPath . '/' . $moduleFolder;
                if (preg_match('|^\.+$|', $moduleFolder) || ! is_dir($currentModuleDir)) {
                    continue;
                }
        
                $moduleClassName = ucwords($moduleFolder);
        
                if (file_exists($currentModuleDir . '/' . 'ModuleInfo.php')) {
                    $class = 'common\modules\\' . $moduleFolder . '\\' . 'ModuleInfo';
                } else {
                    continue;
                }
        
                $instance = null;
                try {
                    $instance = new $class();
                    if (empty($instance->id)) {
                        $instance->id = $moduleFolder;
                    }
                    if (empty($instance->name)) {
                        $instance->name = $moduleFolder;
                    }
                    if ($instance->is_system) {
                        $modularity = Modularity::findOne([
                            'id' => $instance->id
                        ]);
                        if (! $modularity) {
                            $modularity->delete();
                            $instance->uninstall();
                        }
                    }
        
                } catch (Exception $e) {
                    $instance = null;
                }
            }
        }
    }
    
}